package com.kinyx.framework.bean;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.List;

import com.kinyx.framework.annotation.assist.CanNotNull;
import com.kinyx.framework.annotation.assist.CanNull;
import com.kinyx.framework.annotation.assist.ReturnNotNull;
import com.kinyx.framework.reflect.KClassScanner;
import com.kinyx.framework.utils.KListUtils;
import com.kinyx.framework.utils.KMatcherUtils;
import com.kinyx.framework.utils.KStringUtils;

/**
 * 包扫描工具
 */
public final class PackageScaner {

	private class Vo {
		/** 扫描根路径 */
		private String root;
		/** 匹配正则表达式 */
		private String regex;
	}

	private List<Vo> list = new ArrayList<>();

	private Vo toVo(final String config) {
		final Vo vo = new Vo();
		final int indexOf = config.indexOf("*");// 第一个通配符出现的位置
		if (indexOf == -1) {// 不包含通配符
			vo.root = config;
		} else {// 包含通配符
			if (indexOf == 0) {// 以通配符开头，则需要全路径扫描。
			} else {// 其它位置，需要取第一个通配符前最后一个【.】之前的包，作为根路径扫描。
				final String str = config.substring(0, indexOf);
				if (!str.equals("")) {
					final int lastIndexOfDot = str.lastIndexOf(".");
					if (lastIndexOfDot == (str.length() - 1)) {
						vo.root = str.substring(0, str.length() - 1);
					} else {
						vo.root = str.substring(0, lastIndexOfDot);
					}
				}
			}
			vo.regex = config.replaceAll("\\.", "\\\\.").replaceAll("\\*\\*", "(\\\\w+\\\\.){0,}\\\\w+").replaceAll("\\*", "\\\\w{0,}");
		}
		return vo;
	}

	private PackageScaner(final String config) {
		if (config == null) { return; }
		if (config.contains(",")) {
			final String[] arr = config.split(",");
			for (final String str : arr) {
				this.list.add(this.toVo(str));
			}
		} else {
			this.list.add(this.toVo(config));
		}
	}

	@Override
	public String toString() {
		return "[" + KListUtils.join(this.list, ",", (vo, i) -> {
			return "(root: " + vo.root + ", regex: " + vo.regex + ")";
		}) + "]";
	}

	/**
	 * 构造方法（通配符转换正则表达式）
	 * <pre>
	 * 【,】拆分成多个配置
	 * 【.】需要进行转义
	 * 【**】通配多层子包
	 * 【*】通配任意字符
	 * </pre>
	 * @param config 配置值
	 * @return 新对象
	 */
	@ReturnNotNull
	public static PackageScaner of(@CanNull final String config) {
		return new PackageScaner(config);
	}

	/**
	 * 扫描类
	 * @param inJar 是否扫描JAR包
	 * @param scanSubPackage 是否需要扫描子包
	 * @param annotations 只扫描带有注解类的类
	 * @return 类列表
	 */
	@SuppressWarnings("unchecked")
	@ReturnNotNull
	public List<Class<?>> scanClasses(@CanNotNull final boolean inJar, @CanNotNull final boolean scanSubPackage, @CanNull final Class<? extends Annotation>... annotations) {
		final List<Class<?>> results = new ArrayList<>();
		this.list.forEach(vo -> {
			final String packageName = KStringUtils.isBlank(vo.root) ? "" : vo.root;
			final List<Class<?>> scanClasses = KClassScanner.scanClasses(packageName, inJar, scanSubPackage, annotations);
			if (vo.regex == null) {
				scanClasses.forEach(cls -> {
					results.add(cls);
				});
			} else {
				scanClasses.forEach(cls -> {
					// 不满足通配符转换的正则表达式，则需要跳过。
					if (KMatcherUtils.matches(cls.getPackage().getName(), vo.regex)) {
						results.add(cls);
					}
				});
			}
		});
		return results;
	}

}
